package com.zyl.blog.common.handler;


import com.zyl.blog.common.annotation.Sensitive;
import com.zyl.blog.common.enums.SensitiveType;
import com.zyl.blog.common.response.DesensitizeWrapper;
import com.zyl.blog.common.strategy.SensitiveStrategy;
import com.zyl.blog.common.utils.Extreme.LogUtil;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 脱敏处理器
 * 负责对对象进行脱敏处理
 * @version v1.0
 * @ProjectName: Personal_BLogUtil_Server
 * @Package: com.zyl.bLogUtil.common.handler
 * @ClassName: DesensitizationHandler
 * @Author FinalFantasy
 * @Date 2025/9/8-10:21
 */
@Slf4j
public class DesensitizationHandler {

    /**
     * 缓存「类→敏感字段列表」，避免重复反射获取字段（核心优化）
     * key：目标类（如UserInfoVO），value：该类中带@Sensitive的字段
     */
    private final Map<Class<?>, List<Field>> SENSITIVE_FIELD_CACHE = new ConcurrentHashMap<>();

    /**
     * 优化后：精准脱敏入口
     */
    public <T> T desensitize(T obj) {
        switch (obj) {
            case null -> {
                return null;
            }

            /* 处理「包装类」（如Result）：直接穿透到data字段，不遍历其他字段 */
            case DesensitizeWrapper<?> desensitizeWrapper -> {
                LogUtil.info("识别到脱敏包装类：{}，直接处理核心数据", obj.getClass().getSimpleName());
                Object wrappedData = desensitizeWrapper.getWrappedData();
                desensitize(wrappedData);

                return obj;
            }


            /* 处理集合（List/Set）：遍历元素，每个元素单独脱敏 */
            case Collection<?> objects -> {
                objects.forEach(this::desensitize);
                return obj;
            }
            default -> {
            }
        }

        /* 处理数组：遍历元素，每个元素单独脱敏 */
        if (obj.getClass().isArray()) {
            int length = Array.getLength(obj);
            for (int i = 0; i < length; i++) {
                desensitize(Array.get(obj, i));
            }
            return obj;
        }

        /* 跳过「无需处理的类型」：基本类型/String/系统类（java.开头） */
        Class<?> clazz = obj.getClass();
        if (clazz.isPrimitive() || clazz == String.class ||
                clazz.getName().startsWith("java.") || clazz.getName().startsWith("javax.")) {
            return obj;
        }

        /* 处理「普通自定义对象」（如UserInfoVO）：只处理带@Sensitive的字段 */
        handleSensitiveObject(obj, clazz);
        return obj;
    }

    /**
     * 处理普通自定义对象：只加载并处理缓存的敏感字段
     */
    private void handleSensitiveObject(Object obj, Class<?> clazz) {
        try {
            /* 从缓存获取敏感字段：第一次获取后缓存，后续直接复用（减少反射开销） */
            List<Field> sensitiveFields = SENSITIVE_FIELD_CACHE.computeIfAbsent(clazz, this::getSensitiveFields);

            if (sensitiveFields.isEmpty()) {
                LogUtil.info("对象[{}]无敏感字段，直接跳过", clazz.getSimpleName());
                return;
            }

            LogUtil.info("对象[{}]存在{}个敏感字段，开始处理", clazz.getSimpleName(), sensitiveFields.size());
            /* 遍历敏感字段，非敏感字段直接跳过 */
            for (Field field : sensitiveFields) {
                /* 缓存时已处理，此处可直接用 */
                field.setAccessible(true);
                Object fieldValue = field.get(obj);

                /* 处理字段本身的脱敏（如UserInfoVO的email） */
                handleSensitiveField(obj, field);

                /* 若字段值是复杂对象（如UserInfoVO的socialLinks(Map)、roles(List<RoleVO>)），递归处理其敏感字段 */
                desensitize(fieldValue);
            }

        } catch (Exception e) {
            LogUtil.error("对象[{}]脱敏失败", null, clazz.getSimpleName(), e);
            throw new RuntimeException("数据脱敏处理失败", e);
        }
    }

    /**
     * 反射获取类中所有带@Sensitive注解的字段（只执行一次，缓存复用）
     */
    private List<Field> getSensitiveFields(Class<?> clazz) {
        List<Field> sensitiveFields = new ArrayList<>();
        Field[] allFields = clazz.getDeclaredFields();

        for (Field field : allFields) {
            if (field.isAnnotationPresent(Sensitive.class)) {
                field.setAccessible(true); // 提前设置可访问，避免后续重复调用
                sensitiveFields.add(field);
            }
        }
        LogUtil.info("初始化对象[{}]的敏感字段缓存，共{}个", clazz.getSimpleName(), sensitiveFields.size());
        return sensitiveFields;
    }

    /**
     * 原有逻辑：处理单个敏感字段的脱敏（无需修改，复用）
     */
    private void handleSensitiveField(Object obj, Field field) throws IllegalAccessException {
        Sensitive annotation = field.getAnnotation(Sensitive.class);
        Object fieldValue = field.get(obj);
        Class<?> fieldType = field.getType();
        String originalValue;

        /* 处理字段值，统一转为String（仅支持String和LocalDate，LocalDate需先转String） */
        if (fieldValue == null) {
            LogUtil.info("字段：{}.{} 值为null，跳过脱敏", obj.getClass().getSimpleName(), field.getName());
            return;
        } else if (fieldType == String.class) {
            originalValue = (String) fieldValue;
        } else if (fieldType == LocalDate.class) {
            /* 若仍有其他LocalDate字段，先转为String，后续返回时需改为String类型 */
            originalValue = ((LocalDate) fieldValue).format(DateTimeFormatter.ISO_LOCAL_DATE);
            LogUtil.warn("字段：{}.{} 类型为LocalDate，建议改为String以支持脱敏",
                    obj.getClass().getSimpleName(), field.getName());
        } else {
            LogUtil.warn("字段：{}.{} 类型[{}]不支持脱敏，跳过",
                    obj.getClass().getSimpleName(), field.getName(), fieldType.getSimpleName());
            return;
        }

        /* 执行脱敏 */
        LogUtil.info("开始脱敏字段：{}.{}（类型：{}）",
                obj.getClass().getSimpleName(), field.getName(), annotation.type());
        String maskedValue = getMaskedValue(originalValue, annotation);

        /* 直接赋值（字段已改为String，无需转回LocalDate） */
        field.set(obj, maskedValue);
        LogUtil.info("      字段：{}.{} 脱敏完成",
                obj.getClass().getSimpleName(), field.getName());
    }

    /**
     * 原有逻辑：根据注解获取脱敏值（无需修改，复用）
     */
    private String getMaskedValue(String value, Sensitive annotation) {
        SensitiveType type = annotation.type();
        SensitiveStrategy strategy;

        /* 处理内置类型 */
        if (type != SensitiveType.CUSTOM) {
            strategy = type.getStrategy();
            if (strategy == null) {
                throw new RuntimeException("脱敏类型[" + type.name() + "]未配置策略");
            }
        }
        /* 处理自定义类型 */
        else {
            Class<? extends SensitiveStrategy> strategyClass = annotation.strategy();
            /* 校验策略类合法性 */
            if (strategyClass.isInterface() || Modifier.isAbstract(strategyClass.getModifiers())) {
                throw new RuntimeException("自定义策略不能是接口/抽象类：" + strategyClass.getName());
            }
            try {
                /* 实例化自定义策略（无参构造） */
                strategy = strategyClass.getDeclaredConstructor().newInstance();
            } catch (Exception e) {
                throw new RuntimeException("创建自定义策略失败：" + strategyClass.getSimpleName(), e);
            }
        }

        return Objects.requireNonNull(strategy).desensitize(value, annotation);
    }
}
